package com.hxs.hxsserver.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.google.gson.Gson;
import com.hxs.hxsserver.config.redis.RedisService;
import com.hxs.hxsserver.domain.dto.device.AlarmData;
import com.hxs.hxsserver.domain.dto.device.DeviceSSEDto;
import com.hxs.hxsserver.domain.entity.device.*;
import com.hxs.hxsserver.domain.entity.relay.Relay;
import com.hxs.hxsserver.domain.entity.user.User;
import com.hxs.hxsserver.mapper.device.*;
import com.hxs.hxsserver.mapper.relay.RelayMapper;
import com.hxs.hxsserver.service.DeviceCommandLogHistoryService;
import com.hxs.hxsserver.service.DeviceService;
import com.hxs.hxsserver.service.SSEService;
import com.hxs.hxsserver.socketServer.SocketServer;
import com.hxs.hxsserver.utils.ByteUtil;
import com.hxs.hxsserver.utils.EmailSender;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * SSE连接
 * @author liuchuan
 * @create 2024/9/25
 */
@Service
@Slf4j
public class SSEServiceImpl implements SSEService {

    @Resource
    SocketServer socketServer;

    @Resource
    DeviceService deviceService;

    @Resource
    DeviceMapper deviceMapper;

    @Resource
    DeviceCommandLogHistoryService deviceCommandLogHistoryService;

    @Resource
    private RedisService redisService;

    @Resource
    FactorMapper factorMapper;

    @Resource
    FactorHistoryMapper factorHistoryMapper;

    @Resource
    RelayMapper relayMapper;

    @Resource
    DeviceStatusHistoryMapper deviceStatusHistoryMapper;

    @Resource
    AlarmLogMapper alarmLogMapper;


    private final List<PrintWriter> clients = Collections.synchronizedList(new ArrayList<>());
    private Map<String, PrintWriter> browsers = new ConcurrentHashMap<>();
    @Override
    public void streamSSE(HttpServletResponse response, String deviceAddr) throws IOException {
        response.setContentType("text/event-stream");
        response.setCharacterEncoding("UTF-8");
        PrintWriter writer = response.getWriter();
        browsers.put(deviceAddr, writer); // 存储客户端
        synchronized (clients) {
            clients.add(writer);
        }
        try {
            while (true) {
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            // 处理异常
        } finally {
            synchronized (clients) {
                clients.remove(writer);
            }
            writer.close();
        }
    }

    @Override
    public void sendMessage(String message,String deviceHardwareAddr) {
        DeviceSSEDto deviceSSEDto = new DeviceSSEDto();
        deviceSSEDto.setCommand(message);
        deviceSSEDto.setDeviceHardwareAddr(deviceHardwareAddr);
        Gson gson = new Gson();

        String jsonString = gson.toJson(deviceSSEDto);
        //向所有前端发送消息
        for (PrintWriter client : clients) {
            client.write("data: " + jsonString + "\n\n");
            client.flush();
        }

        //向某个具体的客户端发送消息
//        PrintWriter clientWriter = browsers.get(inetAddress); // 查找特定客户端
//        if (clientWriter != null) {
//            clientWriter.write("data: " + message + "\n\n");
//            clientWriter.flush();
//        } else {
//            // 客户端未连接，可以选择记录日志或其他处理
//            log.info("客户端未找到: " + inetAddress);
//        }
    }

    @Override
    public Boolean command(DeviceSSEDto deviceSSEDto) {
        socketServer.sendMessageToClient(deviceSSEDto.getDeviceHardwareAddr(),deviceSSEDto.getCommand());
        return true;
    }

    @Override
    public void updateStatusDevice(String deviceAddr,int stauts) {
        DeviceStatusHistory deviceStatusHistory = new DeviceStatusHistory();
        deviceStatusHistory.setCreateTime(new Date());
        deviceStatusHistory.setDeviceHardwareAddr(deviceAddr);
        LambdaUpdateWrapper<Device> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(Device::getIsDelete,0);
        updateWrapper.eq(Device::getDeviceHardwareAddr,deviceAddr);
        if(stauts == 0){
            updateWrapper.set(Device::getLastOfflineTime,new Date());
            deviceStatusHistory.setStatus(0);
        }else if(stauts == 1){
            updateWrapper.set(Device::getLastOnlineTime,new Date());
            deviceStatusHistory.setStatus(1);
        }
        updateWrapper.set(Device::getDeviceStatus,stauts);
        deviceMapper.update(null,updateWrapper);
        deviceStatusHistoryMapper.insert(deviceStatusHistory);
    }

    @Override
    public Boolean saveOrUpdate(Device device,String messageHex) {
        // 获取第五到第十四个字符（设备唯一地址码）
        String addr = messageHex.substring(4, 14);
        // 数据包
        DeviceCommandLogHistory deviceCommandLogHistory = new DeviceCommandLogHistory(messageHex,device.getDeviceIpAddr(), addr);
        deviceCommandLogHistoryService.insertLog(deviceCommandLogHistory);
        log.info("数据包写入数据库成功");

        if (messageHex.length()== 18) {
            // 长度等于18相当于是心跳包
            LambdaQueryWrapper<Device> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Device::getIsDelete,0);
            queryWrapper.eq(Device::getDeviceHardwareAddr,addr);
            Device deviceOld = deviceMapper.selectOne(queryWrapper);
            if(deviceOld==null){
//                device.setDeviceHardwareAddr(addr);
//                device.setDeviceName(addr);
//                device.setFolderId(1);
//                device.setUserId(1);
//                device.setLastOnlineTime(new Date());
//                deviceService.insertDevice(device);
//                log.info("设备信息新增成功");
                return false;
            }else {
                LambdaUpdateWrapper<Device> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
                lambdaUpdateWrapper.eq(Device::getDeviceHardwareAddr,addr);
                lambdaUpdateWrapper.eq(Device::getIsDelete,0);
                lambdaUpdateWrapper.set(Device::getDeviceStatus,1);
                lambdaUpdateWrapper.set(Device::getLastOnlineTime,new Date());
                //更新设备状态为在线
                deviceMapper.update(null,lambdaUpdateWrapper);
            }
            LambdaQueryWrapper<DeviceStatusHistory> deviceStatusHistoryLambdaQueryWrapper = new LambdaQueryWrapper<>();
            deviceStatusHistoryLambdaQueryWrapper.eq(DeviceStatusHistory::getDeviceHardwareAddr,addr);
            deviceStatusHistoryLambdaQueryWrapper.orderByDesc(DeviceStatusHistory::getCreateTime);
            deviceStatusHistoryLambdaQueryWrapper.last("LIMIT 1");
            DeviceStatusHistory deviceStatusHistory1 = deviceStatusHistoryMapper.selectOne(deviceStatusHistoryLambdaQueryWrapper);
            if(deviceStatusHistory1 == null || deviceStatusHistory1.getStatus()==0){
                DeviceStatusHistory deviceStatusHistory = new DeviceStatusHistory();
                deviceStatusHistory.setCreateTime(new Date());
                deviceStatusHistory.setDeviceHardwareAddr(addr);
                deviceStatusHistory.setStatus(1);
                deviceStatusHistoryMapper.insert(deviceStatusHistory);
            }
        } else {
            //获取有效字节数据区，04代表两个数据区，一个数据区两个字节
            String effective = messageHex.substring(18, 20);
            //获取功能码
            String funNo = messageHex.substring(16, 18);
            //03代表16位整数  03,04是数据包，05,06是开关控制
            if("03".equalsIgnoreCase(funNo)){
                //获取节点码
                int nodet = ByteUtil.hexToDecimal(messageHex.substring(14, 16));
                int sort = 1;
                //转10进制，获取几个数据区
                int i = ByteUtil.hexToDecimal(effective)/2;
                for (int j = 0; j < i; j++) {
                    //截取单个因子信息
                    String substring2 = messageHex.substring(20+j*4, 24 + j*4);
                    int data = ByteUtil.hexToDecimal(substring2);
                    FactorHistory factorHistory = new FactorHistory();
                    factorHistory.setValue(data);
                    factorHistory.setDeviceHardwareAddr(addr);
                    factorHistory.setNodeNo(nodet);
                    //存数据区间
                    factorHistory.setSort(sort);
                    factorHistoryMapper.insert(factorHistory);
                    emailSender(addr,nodet,sort,data);
                    sort++;
                }
            }else if("04".equalsIgnoreCase(funNo)){
                //获取节点码
                int nodet = ByteUtil.hexToDecimal(messageHex.substring(14, 16));
                //04代表32位整数
                int sort = 1;
                //转10进制，获取几个数据区
                int i = ByteUtil.hexToDecimal(effective)/4;
                for (int j = 0; j < i; j++) {
                    //截取单个因子信息
                    String substring2 = messageHex.substring(20+j*8, 28 + j*8);
                    Long data = ByteUtil.hexToDecimal32(substring2);
                    FactorHistory factorHistory = new FactorHistory();
                    factorHistory.setValue(data);
                    factorHistory.setDeviceHardwareAddr(addr);
                    factorHistory.setNodeNo(nodet);
                    //存数据区间
                    factorHistory.setSort(sort);
                    factorHistoryMapper.insert(factorHistory);
                    emailSender(addr,nodet,sort,data);
                    sort++;
                }
            }else if("05".equalsIgnoreCase(funNo)){
                //获取节点码
                int nodet = ByteUtil.hexToDecimal(messageHex.substring(20, 22));
                //单个继电器开关控制功能
                //开关状态01是开，00是关
                String status = messageHex.substring(22, 24);

                LambdaUpdateWrapper<Relay> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(Relay::getDeviceHardwareAddr,addr);
                updateWrapper.eq(Relay::getRelayNo,nodet);
                if("01".equals(status)){
                    updateWrapper.set(Relay::getStatus,1);
                }else if("00".equals(status)){
                    updateWrapper.set(Relay::getStatus,0);
                }
                relayMapper.update(null,updateWrapper);
                log.info("单个继电器开关控制成功");
            }else if("06".equalsIgnoreCase(funNo)){
                //所有继电器开关控制功能
                //开关状态FF是全开，00是关
                String status = messageHex.substring(22, 24);
                LambdaUpdateWrapper<Relay> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(Relay::getDeviceHardwareAddr,addr);
                if("FF".equals (status)){
                    updateWrapper.set(Relay::getStatus,1);
                }else if("00".equals(status)){
                    updateWrapper.set(Relay::getStatus,0);
                }
                relayMapper.update(null,updateWrapper);
                log.info("所有继电器开关控制成功");
            }else if("02".equalsIgnoreCase(funNo)){
                //获取节点码
                int nodet = ByteUtil.hexToDecimal(messageHex.substring(14, 16));
                //新增布尔类型因子
                int sort = 1;
                //转10进制，获取几个数据区
                int i = ByteUtil.hexToDecimal(effective);
                for (int j = 0; j < i; j++) {
                    //截取单个因子信息
                    String substring2 = messageHex.substring(20+j*2, 22 + j*2);
                    int data = ByteUtil.hexToDecimal(substring2);
                    FactorHistory factorHistory = new FactorHistory();
                    factorHistory.setValue(data);
                    factorHistory.setDeviceHardwareAddr(addr);
                    factorHistory.setNodeNo(nodet);
                    //存数据区间
                    factorHistory.setSort(sort);
                    factorHistoryMapper.insert(factorHistory);
                    sort++;
                }
            }

            //todo 后续还需要加罗辑
            LambdaUpdateWrapper<Device> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            lambdaUpdateWrapper.eq(Device::getDeviceHardwareAddr,addr);
            lambdaUpdateWrapper.eq(Device::getIsDelete,0);
            lambdaUpdateWrapper.set(Device::getDeviceStatus,1);
            //更新设备状态为在线
            deviceMapper.update(null,lambdaUpdateWrapper);
            log.info("设备状态更新成功");
        }

        return true;
    }

    //检验是否超过预警值，并发送邮件
    public void emailSender(String addr, int node, int sort, long data) {
        AlarmData alarmRule = factorMapper.getAlarmRule(addr, node, sort);
        if (alarmRule == null) {
            return;
        }
        try {
            String dataCondition = alarmRule.getDataCondition();
            String dataUpperLimitStr = alarmRule.getDataUpperLimit();
            String coefficientStr = alarmRule.getCoefficient();
            String deviationStr = alarmRule.getDeviation();
            String digitStr = alarmRule.getDigit();
            String deviceName = alarmRule.getDeviceName();
            String factorName = alarmRule.getFactorName();

            if (dataCondition == null || dataUpperLimitStr == null || coefficientStr == null || deviationStr == null || digitStr == null || deviceName == null || factorName == null) {
                // 添加日志记录
                log.info("Missing required fields in alarm rule for addr: " + addr + ", node: " + node + ", sort: " + sort);
                return;
            }
            int dataUpperLimit = Integer.parseInt(alarmRule.getDataUpperLimit());
            BigDecimal coefficient = new BigDecimal(alarmRule.getCoefficient());
            BigDecimal deviation = new BigDecimal(alarmRule.getDeviation());
            int digit = Integer.parseInt(alarmRule.getDigit());

            boolean shouldSendEmail = false;
            if ("01".equals(dataCondition) && data < dataUpperLimit) {
                shouldSendEmail = true;
            } else if ("03".equals(dataCondition) && data > dataUpperLimit) {
                shouldSendEmail = true;
            }

            if (shouldSendEmail) {
                User user = factorMapper.getUser(addr);
                if (user != null && user.getEmail() != null) {
                    // 新增报警记录
                    AlarmLog alarmLog = new AlarmLog();
                    alarmLog.setDeviceHardwareAddr(addr);

                    // 计算结果
                    BigDecimal value = BigDecimal.valueOf(data);
                    BigDecimal result = value.multiply(coefficient).add(deviation).setScale(digit, RoundingMode.HALF_UP); // 四舍五入保留小数

                    // 组装数据描述
                    alarmLog.setDescription("设备：" + deviceName + ",  因子：" + factorName +", 节点编号："+alarmRule.getNodeId() +", 排序："+alarmRule.getSort()+ ",  值：" + result +alarmRule.getUnit() + ",  超出阈值");
                    alarmLog.setUserId(user.getId());
                    alarmLog.setData(result+alarmRule.getUnit());
                    alarmLog.setCreateTime(new Date());
                    alarmLog.setStatus(0);
                    alarmLogMapper.insert(alarmLog);

                    EmailSender.EmailSender(user.getEmail(),alarmLog.getDescription());
                } else {
                    // 添加日志记录
                    log.info("User not found or email is null for addr: " + addr);
                }
            }
        } catch (NumberFormatException e) {
            // 添加日志记录
            log.info("NumberFormatException occurred while parsing alarm rule values for addr: " + addr + ", node: " + node + ", sort: " + sort);
            e.printStackTrace();
        }
    }


}
